package com.sansecy.monitor.interceptor;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;

import com.sansecy.monitor.see.LogBean;
import com.sansecy.monitor.see.See;
import com.sansecy.monitor.utils.JsonUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.GzipSource;

/**
 * @Description See工具的日志拦截器
 * @Date 2019-08-03 23:14
 * @Created by caoyu
 */
public class SeeLogInterceptor implements Interceptor {

    private static final Charset UTF8 = Charset.forName("UTF-8");

    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        int logId = View.generateViewId();
        Request request = chain.request();
        //发出请求的时间
        long startNs = System.nanoTime();

        Response response;
        LogBean logBean = null;
        try {
            logBean = obtainRequest(logId, request);
            response = chain.proceed(request);
            logBean = obtainRequest(logId, response.request());
            logBean.setStatusCode(String.valueOf(response.code()));
            logBean.setMessage(response.message());
            buildResult(logBean, response, startNs);
            if (response.isSuccessful()) {
                See.showNormal(logId, logBean);
            } else {
                See.showError(logId, logBean);
            }
        } catch (IOException e) {
            if (logBean == null) {
                logBean = new LogBean();
                logBean.setId(logId);
            }
            buildResult(logBean, null, startNs);
            //追加错误信息
            logBean.setException(e);
            See.showError(logId, logBean);
            throw e;
        }

        return response;
    }

    private void buildResult(LogBean logBean, @Nullable Response response, long startNs) throws IOException {
        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
        logBean.setTookTime(tookMs);
        if (response != null) {
            ResponseBody responseBody = response.body();
            Charset charset = UTF8;
            String type = null;
            String subType = null;
            if (responseBody != null) {
                MediaType contentType = responseBody.contentType();
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                    logBean.setResponseMediaType(contentType.toString());
                    type = contentType.type();
                    subType = contentType.subtype();
                }
            }
            if ("text".equals(type) || "application".equals(type) && "json".equals(subType)) {
                BufferedSource source = responseBody.source();
                source.request(Long.MAX_VALUE); // Buffer the entire body.
                Buffer buffer = source.buffer();
                Headers headers = response.headers();
                Long gzippedLength = null;
                if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
                    gzippedLength = buffer.size();
                    GzipSource gzippedResponseBody = null;
                    try {
                        gzippedResponseBody = new GzipSource(buffer.clone());
                        buffer = new Buffer();
                        buffer.writeAll(gzippedResponseBody);
                    } finally {
                        if (gzippedResponseBody != null) {
                            gzippedResponseBody.close();
                        }
                    }
                }
                assert charset != null;
                String json = buffer.clone().readString(charset);

                if (needDecrypt(logBean.getHost())) {
                    //需要解密
                    String decryptResponse = getDecryptResponse(json);
                    String formatJson = JsonUtils.stringToJSON(decryptResponse);
                    logBean.setDecryptResponse(formatJson);
                } else {
                    String formatJson = JsonUtils.stringToJSON(json);
                    logBean.setResponseBody(formatJson);
                }
                if (gzippedLength != null) {
                    logBean.setGzipSize(gzippedLength);
                    double kb = gzippedLength / 1014D;
                    logBean.setTrafficSize(String.format(Locale.getDefault(), "%.2f kb", kb));
                }
            }
        }
    }


    private LogBean obtainRequest(int logId, Request request) throws IOException {
        //构建请求参数区域
        HttpUrl url = request.url();
        LogBean logBean = new LogBean();
        logBean.setId(logId);
        logBean.setHost(url.host());
        logBean.setMethod(request.method());
        logBean.setUrl(url.toString());
        logBean.setPath(url.encodedPath());
        logBean.setRequestTime(System.currentTimeMillis());
        RequestBody requestBody = request.body();
        if (requestBody != null) {
            MediaType contentType = requestBody.contentType();
            if (contentType != null) {
                logBean.setRequestMediaType(contentType.toString());
            }
            Charset charset = null;
            String type = null;
            if (contentType != null) {
                charset = contentType.charset(UTF8);
                type = contentType.type();
            }
            if ("application".equals(type)) {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                assert charset != null;
                String requestParam = buffer.readString(charset);

                if (needDecrypt(url.host())) {
                    String[] split = requestParam.split("=");
                    for (int i = 0; i < split.length; i++) {
                        String string = split[i];
                        if (i == 1) {
                            String decryptParams = getDecryptParams(string);
                            String paramValue = JsonUtils.stringToJSON(decryptParams);
                            logBean.setDecryptParams(paramValue);
                        }
                    }
                } else {
                    try {
                        requestParam = new java.net.URI(requestParam).getPath();
                    } catch (URISyntaxException e) {
                        Log.d(this.getClass().getName(), "intercept:URISyntaxException " + e.getMessage());
                    }
                }
                logBean.setFullUrl(url + "?" + requestParam);
            }
        }

        See.showNormal(logId, logBean);
        return logBean;
    }

    private void ontainResponse() {

    }


    protected boolean needDecrypt(String host) {
        return false;
    }

    protected String getDecryptResponse(String json) {
        return "";
    }

    protected String getDecryptParams(String params) {
        return "";
    }

}
